package config

import (
	"errors"
	"github.com/gomodule/redigo/redis"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"time"
)

type Configuration struct {
	Logger LogLevel
	System System
	Pgsql  Pgsql
	Redis  Redis
	Etcd   Etcd
}

type System struct {
	Port string
	ServiceName string
	ServiceAddr string
}

type LogLevel struct {
	Level string
}

type Etcd struct {
	Host string
	Port string
}

type Pgsql struct {
	Host         string
	Port         string
	Config       string
	Dbname       string
	Username     string
	Password     string
	MaxIdleConns int // 空闲中的最大连接数
	MaxOpenConns int // 打开到数据库的最大连接数
}

type Redis struct {
	Host     string
	Port     string
	Dbname   int
	Password string
	Type     string
}

func (p *Pgsql) PgsqlDsn() string {
	return "host=" + p.Host + " user=" + p.Username + " password=" + p.Password + " dbname=" + p.Dbname + " port=" + p.Port + " " + p.Config
}

func (p *Pgsql) PgsqlDb() (*gorm.DB, error) {
	if p.Dbname == "" {
		return nil, errors.New("dbname error")
	}
	pgsqlConfig := postgres.Config{
		DSN:                  p.PgsqlDsn(),
		PreferSimpleProtocol: false,
	}
	var ormLogger  logger.Interface
	ormLogger = logger.Default.LogMode(logger.Info)
	if db, err := gorm.Open(postgres.New(pgsqlConfig), &gorm.Config{
		Logger: ormLogger,
	}); err != nil {
		return nil, err
	} else {
		sqlDB, err := db.DB()
		if err != nil {
			return nil, err
		}
		sqlDB.SetMaxIdleConns(p.MaxIdleConns)
		sqlDB.SetMaxOpenConns(p.MaxOpenConns)
		return db, nil
	}
}

func (r *Redis) RedisDb() (*redis.Pool, error) {
	db := &redis.Pool{
		MaxIdle:     16,                //最初的连接数量
		MaxActive:   0,                 //连接池最大连接数量,不确定可以用0（0表示自动定义）
		IdleTimeout: 300 * time.Second, //连接关闭时间 300秒 （300秒不使用自动关闭）
		Dial: func() (redis.Conn, error) { //要连接的redis数据库
			c, err := redis.Dial(r.Type, r.Host+":"+r.Port)
			if err != nil {
				return nil, err
			}
			if r.Password != "" {
				if _, err := c.Do("AUTH", r.Password); err != nil {
					_ = c.Close()
					return nil, err
				}
			}
			if r.Dbname != 0 {
				if _, err := c.Do("SELECT", r.Dbname); err != nil {
					_ = c.Close()
					return nil, err
				}
			}
			return c, nil
		},
	}
	return db, nil
}
